package library.base.mvp.v.fragment;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;

import butterknife.ButterKnife;
import butterknife.Unbinder;
import library.base.mvp.IContract;
import library.base.mvp.presenter.BasePresenter;
import library.base.mvp.presenter.PresenterManager;
import library.base.mvp.presenter.event.BaseEvent;
import library.common.util.LogUtils;

/**
 * @author Created by qiang.hou on 2018/3/2.
 * @version 1.0
 */
public abstract class BaseFragment<P extends BasePresenter> extends Fragment implements IContract.IView {
    public final static String ARGUMENT = "argument";
    /**
     * argument from this fragment's owner.
     */
    public static String initArgument;
    /**
     * cache the root view
     */
    private View mRootView = null;

    protected P mPresenter;

    /**
     * if the fragment initiated (for lazy loading data)
     */
    protected boolean isViewInitiated;

    /**
     * if the fragment data loaded (for lazy loading data)
     */
    protected boolean isDataLoaded = false;

    protected Unbinder unbinder = null;

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LogUtils.i(getSimpleTag(), "sky_dreaming on onCreate fragment = "
                + getSimpleTag());

        /*
         * Bundle bundle = new Bundle(); bundle.putString(ARGUMENT, argument);
         * fragment contentFragment = new ContentFragment();
         * fragment.setArguments(bundle);
         */
        Bundle bundle = getArguments();
        if (bundle != null) {
            initArgument = bundle.getString(ARGUMENT);
        }
    }

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        if (mRootView == null) {
            if (returnLayoutId() > 0) {
                mRootView = inflater
                        .inflate(returnLayoutId(), container, false);
            }
        }
        if (null != mRootView) {
            /*
             * 缓存的view需要判断是否已经被加过parent，如果有parent需要从parent删除，
             * 要不然会发生这个view已经有parent的错误。
             */
            ViewGroup parent = (ViewGroup) mRootView.getParent();
            if (parent != null) {
                parent.removeView(mRootView);
            }

            unbinder = ButterKnife.bind(this, mRootView);
            initView(mRootView);
            setListener();
        }
        registerPresenter();
        return mRootView;
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        /*
         *  (for lazy loading data)
         */
        isViewInitiated = true;
        prepareRequestData();
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        /*
         *  (for lazy loading data)
         */
        prepareRequestData();
    }

    @Override
    public void onStart() {
        super.onStart();
    }

    @Override
    public void onResume() {
        super.onResume();
    }

    @Override
    public void onPause() {
        super.onPause();
    }

    @Override
    public void onStop() {
        super.onStop();
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        unregisterPresenter();
        unbinder.unbind();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        LogUtils.i(getSimpleTag() + "finalized....");
    }

    @Override
    public void onDetach() {
        super.onDetach();
    }

    /**
     * prepare to get data (for lazy loading data)
     */
    public void prepareRequestData() {
        // set param true: force update data when fragment visible
        prepareRequestData(false);
    }

    /**
     * prepare to get data (for lazy loading data)
     *
     * @param forceUpdate true: force update data when fragment visible
     */
    public void prepareRequestData(boolean forceUpdate) {
        if (getUserVisibleHint() && isViewInitiated && (!isDataLoaded || forceUpdate)) {
            initProcess();
            isDataLoaded = true;
        }
    }

    /**
     * get class name
     *
     * @return class name
     */
    public String getSimpleTag() {
        return getClass().getPackage().getName() + this.getClass().getSimpleName();
    }

    /**
     * register EventBus
     */
    private void registerEventBus() {
        EventBus.getDefault().register(this);
    }

    /**
     * unregister EventBus
     */
    private void unregisterEventBus() {
        if (EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().unregister(this);
        }
    }

    /**
     * receive Event Message
     *
     * @param event BaseEvent
     * @param <E>   BaseEvent
     */
    @Subscribe
    @Override
    public <E extends BaseEvent> void onEventMessageReceive(E event) {
        if (null == event || !event.eventTag.equals(getSimpleTag())) {
            return;
        }
        switch (event.actionTag) {
            case BaseEvent.ACTION_TAG_INIT_PROCESS:
                // do sth init view
                initDataView(event);
                break;
            default:
                onHandleMessage(event);
                break;
        }
    }

    /**
     * register presenter
     */
    @SuppressWarnings("unchecked")
    public void registerPresenter() {
        if (needEventBus()) {
            registerEventBus();
        }
        mPresenter = (P) PresenterManager.getInstance().getPresenter(getSimpleTag());
        if (null == mPresenter) {
            mPresenter = createPresenter();
            if (null != mPresenter) {
                PresenterManager.getInstance().addPresenter(getSimpleTag(), mPresenter);
            }
        }
        if (null != mPresenter) {
            mPresenter.registerViewEvent(getSimpleTag());
        }
    }

    /**
     * unregister presenter
     */
    public void unregisterPresenter() {
        if (null != mPresenter) {
            mPresenter.unRegisterViewEvent(getSimpleTag());
        }
        unregisterEventBus();
    }

    /**
     * Init data and process
     */
    protected void initProcess() {
        if (null != mPresenter) {
            mPresenter.doInitProcess();
        }
    }

    /**
     * set listener to view
     */
    protected void setListener() {
    }

    /**
     * Init data and refresh view
     *
     * @param event BaseEvent
     * @param <E>   BaseEvent
     */
    protected <E extends BaseEvent> void initDataView(E event) {
    }

    /**
     * Init views
     */
    protected abstract void initView(View view);

    /**
     * receive and handle EventBus message
     *
     * @param event BaseEvent
     * @param <E>   BaseEvent
     */
    protected abstract <E extends BaseEvent> void onHandleMessage(E event);

    /**
     * get layout id
     *
     * @return layout resource id
     */
    protected abstract int returnLayoutId();

    /**
     * create Presenter
     *
     * @return P
     */
    protected abstract P createPresenter();

    /**
     * if this view need EventBus
     *
     * @return boolean
     */
    protected abstract boolean needEventBus();

    /**
     * start next activity
     *
     * @param intent            intent
     * @param needForResult     if call startActivityForResult
     * @param requestCode       requestCode for startActivityForResult
     * @param enterAnim         enter animation
     * @param exitAnim          exit animation
     * @param needFinishCurrent if need finish current page
     */
    @SuppressWarnings("unused")
    public void startNextActivity(Intent intent, boolean needForResult,
                                  int requestCode, int enterAnim, int exitAnim, boolean needFinishCurrent) {
        if (needForResult) {
            startActivityForResult(intent, requestCode);
        } else {
            startActivity(intent);
        }
        if (enterAnim > 0 && exitAnim > 0) {
            if (null != getActivity())
                getActivity().overridePendingTransition(enterAnim, exitAnim);
        }
        if (needFinishCurrent) {
            if (null != getActivity())
                getActivity().finish();
        }
    }
}
